我們在昨天day31有介紹到startWith
及endWith
的用法,也建議大家將startWith
放置於pipe
底下,避免不可預期的情形發生。
今天我們來寫一個範例,並進一步驗證startWith
擺在不同地方會發生什麼情形!
startWith
及endWith
擺放順序的重要性,我們來寫個例子
- 這裡我們定義一個變數
countDownMaxNum
,來提供scan
的初始值及startWith
使用。- 可參考day12-scan複習如何寫一個倒數計時器。
...
<body>
<button id="start">start</button>
<button id="stop">stop</button>
<h1 id="number">-</h1>
</body>
...
import {
endWith,
from,
fromEvent,
interval,
map,
startWith,
scan,
takeUntil,
takeWhile,
switchMap,
tap,
throwError,
} from 'rxjs';
//elems
const start = document.getElementById('start');
const stop = document.getElementById('stop');
const num = document.getElementById('number');
// RxJS
const start$ = fromEvent(start, 'click');
const stop$ = fromEvent(stop, 'click');
const timer$ = interval(1000);
// === Step1: 建置一個倒數計時器,並宣告一個變數countDownMaxNum提供給scan及startWith使用 ===
const countDownMaxNum = 10;
const countDown$ = timer$.pipe(
map(() => -1),
scan((accu, current) => accu + current, countDownMaxNum),
takeWhile((d) => d > 0),
takeUntil(stop$)
);
// === Step2: 設定click to start,並觀察不同位置的startWith有什麼不同 ===
console.log('=== startWith放在pipe的底部 ===');
const clickStart$ = start$
.pipe(
// 觀察看看startWith放位置(1)及(2)有什麼不同
// startWith(countDownMaxNum), //<-- (1)
switchMap(() => countDown$),
startWith(countDownMaxNum) //<--(2) 現在測試這個位置
)
.subscribe((d) => (num.innerHTML = `${d}`));
startWith
就先拋出初始值countDownMaxNum
,提供顯示在num.innerHTML
之中,所以從頁面可以看到初始值是10
。start
,開始倒數,中途按下stop
,數字靜止。start
,數字從9
開始,而不是我們預期的10
??
startWith
在observable
開始之前,會優先發送一個數值給observer.next()
,因此我們可以如期在頁面初始狀態上,看到10這個數字。
在那之後,startWith
就不會再發送,也因此,當你再度按下start
,數字會直接從9
開始,也就是直接跑scan
送出的值。
...
console.log('=== startWith放在pipe的 "最上層" ===');
const clickStart$ = start$
.pipe(
// 觀察看看startWith放位置(1)及(2)有什麼不同
startWith(countDownMaxNum), //<-- (1) 現在測試這個位置
switchMap(() => countDown$)
// startWith(countDownMaxNum) //<--(2)
)
.subscribe((d) => (num.innerHTML = `${d}`));
startWith
擺在switchMap
之前,startWith
在點擊之前發出訊號10
,間接觸發了switchMap開始計數,才會還沒點擊就先偷跑計數啦!startWith
擺放的位置,確實會影響,因為他會優先於observable
訂閱運作之前,先行發出訊號,如果後方有其他的operator
,自然會將數值傳遞過去,提前運作,造成不可預期的現象。
接下來我會不定期的持續發佈RxJS
的學習心得,也請大家繼續支持!